home *** CD-ROM | disk | FTP | other *** search
/ Sprite 1984 - 1993 / Sprite 1984 - 1993.iso / src / kernel / fs / fsNameOps.c < prev    next >
Encoding:
C/C++ Source or Header  |  1992-12-19  |  24.1 KB  |  817 lines

  1. /* 
  2.  * fsNameOps.c --
  3.  *
  4.  *    This has procedures for the operations done on file names
  5.  *    like open and remove.  The name lookups are done via
  6.  *    Fsprefix_LookupOperation which uses the prefix table to choose the server.
  7.  *
  8.  * Copyright (C) 1987 Regents of the University of California
  9.  * All rights reserved.
  10.  * Permission to use, copy, modify, and distribute this
  11.  * software and its documentation for any purpose and without
  12.  * fee is hereby granted, provided that the above copyright
  13.  * notice appear in all copies.  The University of California
  14.  * makes no representations about the suitability of this
  15.  * software for any purpose.  It is provided "as is" without
  16.  * express or implied warranty.
  17.  */
  18.  
  19. #ifndef lint
  20. static char rcsid[] = "$Header: /cdrom/src/kernel/Cvsroot/kernel/fs/fsNameOps.c,v 9.4 91/09/10 18:22:35 rab Exp $ SPRITE (Berkeley)";
  21. #endif not lint
  22.  
  23.  
  24. #include <sprite.h>
  25. #include <fs.h>
  26. #include <fsio.h>
  27. #include <fsutil.h>
  28. #include <fsNameOps.h>
  29. #include <fsStat.h>
  30. #include <fsprefix.h>
  31. #include <proc.h>
  32. #include <rpc.h>
  33. #include <dbg.h>
  34. #include <string.h>
  35. #include <stdio.h>
  36.  
  37.  
  38. /*
  39.  *----------------------------------------------------------------------
  40.  *
  41.  * Fs_Open --
  42.  *
  43.  *      This routine sets up a Fs_Stream object for the named file.  The
  44.  *      parameters specify the manner in which the stream will be used and
  45.  *      a set of permission bits in case a file needs to be created for
  46.  *      the stream.
  47.  *
  48.  * Results:
  49.  *      An error code, and a pointer to a Fs_Stream object for the file.
  50.  *      This is used in further operations on the file and is released
  51.  *      with Fs_Close
  52.  *
  53.  * Side effects:
  54.  *    The stream is opened.
  55.  *
  56.  *----------------------------------------------------------------------
  57.  */
  58. ReturnStatus
  59. Fs_Open(name, useFlags, type, permissions, streamPtrPtr)
  60.     char     *name;        /* The name of the file to open */
  61.     register int useFlags;    /* Indicates read/write etc. the valid bits 
  62.                  * to include are defined in fs.h */
  63.     int     type;        /* If FS_FILE then any type of file can be 
  64.                  * opened, except if useFlags includes 
  65.                  * FS_CREATE then a regular file will be 
  66.                  * created.  Otherwise only the specified 
  67.                  * type can be opened (or created). */
  68.     int     permissions;    /* A mask indicating the permission bits to 
  69.                  * turn on if the file gets created */
  70.     Fs_Stream     **streamPtrPtr;    /* Contents set to point to a valid stream
  71.                   * or NIL if there was an error. */
  72. {
  73.     register Fs_Stream     *streamPtr;    /* Local copy of stream pointer */
  74.     ReturnStatus     status;        /* Return error code from RPC */
  75.     Fs_OpenArgs         openArgs;    /* Packaged up parameters */
  76.     Fs_OpenResults     openResults;    /* Packaged up results */
  77.     Proc_ControlBlock    *procPtr;    /* Used to get process IDs */
  78.     Fs_NameInfo        *nameInfoPtr;    /* Used to track name and prefix */
  79.  
  80.     *streamPtrPtr = (Fs_Stream *)NIL;
  81.  
  82.     if ((useFlags & FS_EXECUTE) && (useFlags & (FS_WRITE | FS_CREATE))) {
  83.     return(FS_INVALID_ARG);
  84.     }
  85.     
  86.     /*
  87.      * Override the type if user flags indicate special files.
  88.      */
  89.     if (useFlags & FS_NAMED_PIPE_OPEN) {
  90.     printf( "Named pipes (%s) not implemented\n", name);
  91.     return(FS_INVALID_ARG);
  92.     } else if (useFlags & FS_PDEV_MASTER) {
  93.     type = FS_PSEUDO_DEV;
  94.     } else if (useFlags & FS_PFS_MASTER) {
  95.     type = FS_REMOTE_LINK;
  96.     useFlags &= ~FS_FOLLOW;
  97.     }
  98.     /*
  99.      * Make sure we check for write permission before truncating.
  100.      */
  101.     if (useFlags & FS_TRUNC) {
  102.     useFlags |= FS_WRITE;
  103.     }
  104.  
  105.     /*
  106.      * Set up arguments to the Domain specific open routine.  The domain
  107.      * open routine returns streamData used to set up the I/O handle
  108.      * by the client open routine called below.  The stream's nameInfo is
  109.      * set up as a side effect of going through Fsprefix_LookupOperation.
  110.      */
  111.     procPtr = Proc_GetEffectiveProc();
  112.     if (type != FS_SYMBOLIC_LINK && type != FS_REMOTE_LINK) {
  113.     openArgs.permissions    = permissions & procPtr->fsPtr->filePermissions;
  114.     } else {
  115.     openArgs.permissions    = permissions;
  116.     }
  117.     openArgs.useFlags        = useFlags;
  118.     openArgs.type        = type;
  119.     openArgs.clientID        = rpc_SpriteID;
  120.     if (procPtr->genFlags & PROC_FOREIGN) {
  121.     openArgs.migClientID    = procPtr->peerHostID;
  122.     } else {
  123.     openArgs.migClientID    = rpc_SpriteID;
  124.     }
  125.     openResults.streamData    = (ClientData) NIL;
  126.     Fs_SetIDs(procPtr, &openArgs.id);
  127.     nameInfoPtr = mnew(Fs_NameInfo);
  128.  
  129.     status = Fsprefix_LookupOperation(name, FS_DOMAIN_OPEN, useFlags & FS_FOLLOW,
  130.             (Address)&openArgs, (Address)&openResults, nameInfoPtr);
  131.     if (status == SUCCESS) {
  132.     /*
  133.      * Install the stream and then call the client open procedure
  134.      * to complete the setup of the stream's I/O handle
  135.      */
  136.     streamPtr = Fsio_StreamAddClient(&openResults.streamID, rpc_SpriteID,
  137.                  (Fs_HandleHeader *)NIL,
  138.                  useFlags, name, (Boolean *)NIL, (Boolean *)NIL);
  139.     streamPtr->nameInfoPtr = nameInfoPtr;
  140.     Fsutil_HandleUnlock(streamPtr);
  141.     status = (*fsio_StreamOpTable[openResults.ioFileID.type].ioOpen)
  142.             (&openResults.ioFileID, &streamPtr->flags, rpc_SpriteID,
  143.              openResults.streamData, name, &streamPtr->ioHandlePtr);
  144.     if (status == SUCCESS) {
  145.         if (streamPtr->flags & FS_TRUNC) {
  146.         (void)Fs_TruncStream(streamPtr, 0);
  147.         }
  148.         *streamPtrPtr = streamPtr;
  149.         switch (useFlags & (FS_READ | FS_WRITE)) {
  150.         case FS_READ:
  151.             fs_Stats.cltName.numReadOpens ++;
  152.             break;
  153.         case FS_WRITE:
  154.             fs_Stats.cltName.numWriteOpens ++;
  155.             break;
  156.         case (FS_READ | FS_WRITE):
  157.             fs_Stats.cltName.numReadWriteOpens ++;
  158.             break;
  159.         default:
  160.             break;
  161.         }
  162.     } else {
  163.         /*
  164.          * Client open procedure failed.  Clean up the stream.
  165.          */
  166.         Fsutil_HandleLock(streamPtr);
  167.         (void)Fsio_StreamClientClose(&streamPtr->clientList, rpc_SpriteID);
  168.         Fsio_StreamDestroy(streamPtr);
  169.     }
  170.     } else {
  171.     free((Address)nameInfoPtr);
  172.     }
  173.     return(status);
  174. }
  175.  
  176. /*
  177.  *----------------------------------------------------------------------
  178.  *
  179.  * Fs_SetIDs --
  180.  *
  181.  *    Get user ID and group IDs from the proc table.  The FsUserID
  182.  *    struct includes storage for the list of groups.  Alternatively,
  183.  *    it could contain a pointer to the groups in the proc table.
  184.  *
  185.  *    TODO: Byte the bullet and figure out a nice way to pass a
  186.  *    variable length list of groups around.  Then this procedure
  187.  *    would not be needed, and the Fs_ProcessState could be
  188.  *    referenced directly.  The ugliest place to do all this is
  189.  *    in the RPC stubs.
  190.  *
  191.  * Results:
  192.  *    None.
  193.  *
  194.  * Side effects:
  195.  *    Instantiate *idPtr to hold the user and group IDs of the current proc.
  196.  *
  197.  *----------------------------------------------------------------------
  198.  */
  199. void
  200. Fs_SetIDs(procPtr, idPtr)
  201.     Proc_ControlBlock         *procPtr;
  202.     Fs_UserIDs            *idPtr;
  203. {
  204.     register    Fs_ProcessState *fsPtr;
  205.     register    int    *procGroupIDs;
  206.     register    int    *groupPtr;
  207.     register     int     i;
  208.  
  209.     if (procPtr == (Proc_ControlBlock *)NIL) {
  210.     procPtr = Proc_GetEffectiveProc();
  211.     }
  212.     idPtr->user = procPtr->effectiveUserID;
  213.  
  214.     fsPtr = procPtr->fsPtr;
  215.     if (fsPtr == (Fs_ProcessState *)NIL) {
  216.     /*
  217.      * Exiting processes remove swap files after clearing fs state.
  218.      */
  219.     idPtr->numGroupIDs = 0;
  220.     procGroupIDs = (int *)NIL;
  221.     } else {
  222.     idPtr->numGroupIDs = fsPtr->numGroupIDs;
  223.     procGroupIDs = fsPtr->groupIDs;
  224.     }
  225.     for (i = 0, groupPtr = idPtr->group; i < FS_NUM_GROUPS;  i++, groupPtr++) {
  226.     /*
  227.      * The file system state record supports a variable length array of
  228.      * group IDs but here we truncate it...
  229.      */
  230.     if (i < idPtr->numGroupIDs) {
  231.         *groupPtr = *procGroupIDs;
  232.         procGroupIDs++;
  233.     } else {
  234.         *groupPtr = -1;
  235.     }
  236.     }
  237. }
  238.  
  239. /*
  240.  *----------------------------------------------------------------------
  241.  *
  242.  * Fs_Remove --
  243.  *
  244.  *    Remove the named file.  Because each entry in a directory is only
  245.  *    one of many posible references, the disk space for the file may or
  246.  *    may not be freed after this call.   Only when the last link to
  247.  *    the file is removed is the disk space freed up.  This does not
  248.  *    follow links so that links are removed instead of the file
  249.  *    they reference.
  250.  *
  251.  * Results:
  252.  *    An error code.
  253.  *
  254.  * Side effects:
  255.  *    The file is removed
  256.  *
  257.  *----------------------------------------------------------------------
  258.  */
  259. ReturnStatus
  260. Fs_Remove(name)
  261.     char *name;        /* The name of the file to remove */
  262. {
  263.     ReturnStatus status;
  264.     Fs_LookupArgs lookupArgs;
  265.     Proc_ControlBlock *procPtr = Proc_GetEffectiveProc();
  266.  
  267.     lookupArgs.useFlags = FS_DELETE;
  268.     Fs_SetIDs(procPtr, &lookupArgs.id);
  269.     lookupArgs.clientID = rpc_SpriteID;
  270.     if (procPtr->genFlags & PROC_FOREIGN) {
  271.     lookupArgs.migClientID    = procPtr->peerHostID;
  272.     } else {
  273.     lookupArgs.migClientID    = rpc_SpriteID;
  274.     }
  275.     fs_Stats.cltName.removes++;
  276.     status = Fsprefix_LookupOperation(name, FS_DOMAIN_REMOVE, 0,
  277.              (Address)&lookupArgs, (Address)NIL, (Fs_NameInfo *)NIL);
  278.     return(status);
  279. }
  280.  
  281. /*
  282.  *----------------------------------------------------------------------
  283.  *
  284.  * Fs_RemoveDir --
  285.  *
  286.  *    Remove the named directory.  It must be empty, that is it should
  287.  *    only contain entries for itself (.) and its parent (..).
  288.  *
  289.  * Results:
  290.  *    An error code.
  291.  *
  292.  * Side effects:
  293.  *    The directory is removed if possible
  294.  *
  295.  *----------------------------------------------------------------------
  296.  */
  297. ReturnStatus
  298. Fs_RemoveDir(name)
  299.     char *name;        /* The name of the directory to remove */
  300. {
  301.     ReturnStatus status;
  302.     Fs_LookupArgs lookupArgs;
  303.     Proc_ControlBlock *procPtr = Proc_GetEffectiveProc();
  304.  
  305.     lookupArgs.useFlags = FS_DELETE;
  306.     Fs_SetIDs(procPtr, &lookupArgs.id);
  307.     lookupArgs.clientID = rpc_SpriteID;
  308.     if (procPtr->genFlags & PROC_FOREIGN) {
  309.     lookupArgs.migClientID    = procPtr->peerHostID;
  310.     } else {
  311.     lookupArgs.migClientID    = rpc_SpriteID;
  312.     }
  313.     fs_Stats.cltName.removeDirs++;
  314.     status = Fsprefix_LookupOperation(name, FS_DOMAIN_REMOVE_DIR, 0,
  315.              (Address)&lookupArgs, (Address)NIL, (Fs_NameInfo *)NIL);
  316.     return(status);
  317. }
  318.  
  319. /*
  320.  *----------------------------------------------------------------------
  321.  *
  322.  * Fs_MakeDevice --
  323.  *
  324.  *    Make the named device file.  This is the procedure which
  325.  *    does the actual work for the Fs_MakeDevice system call.
  326.  *
  327.  * Results:
  328.  *    An error code.
  329.  *
  330.  * Side effects:
  331.  *    The device file is made
  332.  *
  333.  *----------------------------------------------------------------------
  334.  */
  335. ReturnStatus
  336. Fs_MakeDevice(name, devicePtr, permissions)
  337.     char *name;            /* The name of the directory to make */
  338.     Fs_Device *devicePtr;    /* Specifies device info */
  339.     int permissions;        /* The permissions for the new directory */
  340. {
  341.     ReturnStatus status;    /* Return error code */
  342.     Fs_MakeDeviceArgs makeDevArgs;/* Packaged up parameters */
  343.     Proc_ControlBlock *procPtr;    /* Used to get process IDs */
  344.  
  345.     if (((devicePtr->serverID != FS_LOCALHOST_ID) &&
  346.     (devicePtr->serverID <= 0)) ||
  347.     (devicePtr->type < 0) ||
  348.     (devicePtr->unit < 0)) {
  349.     return(FS_INVALID_ARG);
  350.     }
  351.     procPtr = Proc_GetEffectiveProc();
  352.     makeDevArgs.device         = *devicePtr;
  353.     makeDevArgs.open.permissions= permissions & procPtr->fsPtr->filePermissions;
  354.     Fs_SetIDs(procPtr, &makeDevArgs.open.id);
  355.     makeDevArgs.open.clientID    = rpc_SpriteID;
  356.     if (procPtr->genFlags & PROC_FOREIGN) {
  357.     makeDevArgs.open.migClientID    = procPtr->peerHostID;
  358.     } else {
  359.     makeDevArgs.open.migClientID    = rpc_SpriteID;
  360.     }
  361.  
  362.     fs_Stats.cltName.makeDevices++;
  363.     status = Fsprefix_LookupOperation(name, FS_DOMAIN_MAKE_DEVICE, 0,
  364.              (Address)&makeDevArgs, (Address)NIL, (Fs_NameInfo *)NIL);
  365.     return(status);
  366. }
  367.  
  368. /*
  369.  *----------------------------------------------------------------------
  370.  *
  371.  * Fs_MakeDir --
  372.  *
  373.  *    Make the named directory.  This is the procedure which
  374.  *    does the actual work for the Fs_MakeDir system call.
  375.  *
  376.  * Results:
  377.  *    An error code.
  378.  *
  379.  * Side effects:
  380.  *    The directory is made
  381.  *
  382.  *----------------------------------------------------------------------
  383.  */
  384. ReturnStatus
  385. Fs_MakeDir(name, permissions)
  386.     char *name;        /* The name of the directory to make */
  387.     int permissions;    /* The permissions for the new directory */
  388. {
  389.     ReturnStatus status;    /* Return error code from RPC */
  390.     Fs_OpenArgs openArgs;    /* Packaged up parameters */
  391.     Proc_ControlBlock *procPtr;    /* Used to get process IDs */
  392.  
  393.     procPtr = Proc_GetEffectiveProc();
  394.     openArgs.useFlags = FS_CREATE | FS_EXCLUSIVE | FS_FOLLOW ;
  395.     openArgs.permissions = permissions & procPtr->fsPtr->filePermissions;
  396.     openArgs.type = FS_DIRECTORY;
  397.     Fs_SetIDs(procPtr, &openArgs.id);
  398.     openArgs.clientID = rpc_SpriteID;
  399.     if (procPtr->genFlags & PROC_FOREIGN) {
  400.     openArgs.migClientID    = procPtr->peerHostID;
  401.     } else {
  402.     openArgs.migClientID    = rpc_SpriteID;
  403.     }
  404.     fs_Stats.cltName.makeDirs++;
  405.     status = Fsprefix_LookupOperation(name, FS_DOMAIN_MAKE_DIR, FS_FOLLOW,
  406.             (Address)&openArgs, (Address)NIL, (Fs_NameInfo *)NIL);
  407.     return(status);
  408. }
  409.  
  410. /*
  411.  *----------------------------------------------------------------------
  412.  *
  413.  * Fs_ChangeDir --
  414.  *
  415.  *    Change the process's current directory.  This opens the
  416.  *    new current directory, and if that's successful the
  417.  *    old one is closed.
  418.  *
  419.  * Results:
  420.  *    An error code.
  421.  *
  422.  * Side effects:
  423.  *    Change the current directory.
  424.  *
  425.  *----------------------------------------------------------------------
  426.  */
  427. ReturnStatus
  428. Fs_ChangeDir(pathName)
  429.     char *pathName;
  430. {
  431.     register    Fs_ProcessState *fsPtr;
  432.     Fs_Stream        *newCwdPtr;    /* A stream is used because it has
  433.                      * a reference count and can be
  434.                      * closed with existing routines. */
  435.     ReturnStatus    status;
  436.  
  437.     fsPtr = (Proc_GetEffectiveProc())->fsPtr;
  438.  
  439.     /*
  440.      * FS_EXECUTE permission needed to change to a directory.
  441.      */
  442.     newCwdPtr = (Fs_Stream *)NIL;
  443.     fs_Stats.cltName.chdirs++;
  444.     status = Fs_Open(pathName, FS_EXECUTE | FS_FOLLOW, FS_DIRECTORY, 0,
  445.                   &newCwdPtr);
  446.     if (status) {
  447.     return(status);
  448.     }
  449.     (void)Fs_Close(fsPtr->cwdPtr);
  450.     fsPtr->cwdPtr = newCwdPtr;
  451.     return(SUCCESS);
  452. }
  453.  
  454. /*
  455.  *----------------------------------------------------------------------
  456.  *
  457.  * Fs_Trunc --
  458.  *
  459.  *    Truncate a file to a given length given its pathname.
  460.  *
  461.  * Results:
  462.  *    An error code
  463.  *
  464.  * Side effects:
  465.  *    The files length gets set and any data beyond that is deleted.
  466.  *
  467.  *----------------------------------------------------------------------
  468.  */
  469. ReturnStatus
  470. Fs_Trunc(pathName, length)
  471.     char *pathName;
  472.     int length;
  473. {
  474.     Fs_Stream *streamPtr;
  475.     ReturnStatus status;
  476.  
  477.     streamPtr = (Fs_Stream *)NIL;
  478.     status = Fs_Open(pathName, FS_WRITE | FS_FOLLOW, FS_FILE, 0, &streamPtr);
  479.     if (status != SUCCESS) {
  480.     return(status);
  481.     }
  482.     status = Fs_TruncStream(streamPtr, length);
  483.     (void)Fs_Close(streamPtr);
  484.     return(status);
  485. }
  486.  
  487. /*
  488.  *----------------------------------------------------------------------
  489.  *
  490.  * Fs_TruncStream --
  491.  *
  492.  *    Truncate a file to a given length given an open stream.
  493.  *    This is a thin layer on top of Fs_IOControl that is called
  494.  *    from Fs_Trunc and from Fs_Open.
  495.  *
  496.  * Results:
  497.  *    An error code
  498.  *
  499.  * Side effects:
  500.  *    The files length gets set and any data beyond that is deleted.
  501.  *
  502.  *----------------------------------------------------------------------
  503.  */
  504. ReturnStatus
  505. Fs_TruncStream(streamPtr, length)
  506.     Fs_Stream *streamPtr;
  507.     int length;
  508. {
  509.     ReturnStatus status;
  510.     Proc_ControlBlock *procPtr = Proc_GetEffectiveProc();
  511.     Fs_IOCParam ioctl;
  512.     Fs_IOReply reply;
  513.  
  514.     if (length < 0) {
  515.     return(GEN_INVALID_ARG);
  516.     }
  517.     ioctl.command = IOC_TRUNCATE;
  518.     ioctl.inBuffer = (Address)&length;
  519.     ioctl.inBufSize = sizeof(int);
  520.     ioctl.outBuffer = (Address) NIL;
  521.     ioctl.outBufSize = 0;
  522.     ioctl.format = mach_Format;
  523.     ioctl.procID = procPtr->processID;
  524.     ioctl.familyID = procPtr->familyID;
  525.     ioctl.uid = procPtr->effectiveUserID;
  526.     ioctl.flags = 0;
  527.  
  528.     status = Fs_IOControl(streamPtr, &ioctl, &reply);
  529.     return(status);
  530. }
  531.  
  532. /*
  533.  *----------------------------------------------------------------------
  534.  *
  535.  * Fs_GetAttributes --
  536.  *
  537.  *    Get the attributes of a file given its name.  First the name server
  538.  *    is contacted to get the initial version of the attributes.  Then
  539.  *    the I/O server is contacted to update attributes like the
  540.  *    access and modify times.
  541.  *
  542.  * Results:
  543.  *    An error code and the attributes.
  544.  *
  545.  * Side effects:
  546.  *    None here.
  547.  *
  548.  *----------------------------------------------------------------------
  549.  */
  550.  
  551. ReturnStatus
  552. Fs_GetAttributes(pathName, fileOrLink, attrPtr)
  553.     char *pathName;
  554.     int fileOrLink;        /* FS_ATTRIB_FILE or FS_ATTRIB_LINK */
  555.     Fs_Attributes *attrPtr;
  556. {
  557.     ReturnStatus status;
  558.     Fs_OpenArgs openArgs;
  559.     Proc_ControlBlock *procPtr = Proc_GetEffectiveProc();
  560.     Fs_GetAttrResults getAttrResults;    /* References attrPtr and ioFileID */
  561.     Fs_FileID ioFileID;            /* Returned from name server, indicates
  562.                      * who the I/O server is. */
  563.  
  564.     openArgs.useFlags = (fileOrLink == FS_ATTRIB_LINK) ? 0 : FS_FOLLOW;
  565.     openArgs.permissions = 0;
  566.     openArgs.type = FS_FILE;
  567.     openArgs.clientID = rpc_SpriteID;
  568.     Fs_SetIDs(procPtr, &openArgs.id);
  569.     if (procPtr->genFlags & PROC_FOREIGN) {
  570.     openArgs.migClientID    = procPtr->peerHostID;
  571.     } else {
  572.     openArgs.migClientID    = rpc_SpriteID;
  573.     }
  574.  
  575.     getAttrResults.attrPtr = attrPtr;
  576.     getAttrResults.fileIDPtr = &ioFileID;
  577.  
  578.     /*
  579.      * Get an initial version of the attributes from the name server.
  580.      */
  581.     fs_Stats.cltName.getAttrs++;
  582.     status = Fsprefix_LookupOperation(pathName, FS_DOMAIN_GET_ATTR, openArgs.useFlags,
  583.          (Address)&openArgs, (Address)&getAttrResults,
  584.          (Fs_NameInfo *)NIL);
  585.     if ((status == SUCCESS) &&
  586.     (ioFileID.type > 0 && ioFileID.type <= FSIO_NUM_STREAM_TYPES)) {
  587.     /*
  588.      * Update those with attributes cached at the I/O server.
  589.      * This is suppressed by setting the ioFileID.type < 0
  590.      */
  591.     fs_Stats.cltName.getIOAttrs++;
  592.     status = (*fsio_StreamOpTable[ioFileID.type].getIOAttr)
  593.             (&ioFileID, rpc_SpriteID, attrPtr);
  594. #ifdef lint
  595.     status = Fsrmt_GetIOAttr(&ioFileID, rpc_SpriteID, attrPtr);
  596.     status = FsrmtFileGetIOAttr(&ioFileID, rpc_SpriteID, attrPtr);
  597.     status = Fsio_DeviceGetIOAttr(&ioFileID, rpc_SpriteID, attrPtr);
  598.     status = Fsio_PipeGetIOAttr(&ioFileID, rpc_SpriteID, attrPtr);
  599. #endif lint
  600.     }
  601.     return(status);
  602. }
  603.  
  604. /*
  605.  *----------------------------------------------------------------------
  606.  *
  607.  * Fs_SetAttributes --
  608.  *
  609.  *    Set some attributes of a file given its name.  The input contains
  610.  *    the complete set of attributes for the file but not all of these
  611.  *    are affected by this call.  Ie.  the user can't change everything.
  612.  *    The name server is contacted first to set attributes file descriptor,
  613.  *    then the I/O server is contacted to update cached attributes.
  614.  *
  615.  * Results:
  616.  *    An error code
  617.  *
  618.  * Side effects:
  619.  *    See FsLocalSetAttrID for which attributes get updated at the
  620.  *    file server.
  621.  *
  622.  *     If the operation is successful, the count of setAttrs is incremented.
  623.  *
  624.  *----------------------------------------------------------------------
  625.  */
  626. ReturnStatus
  627. Fs_SetAttributes(pathName, fileOrLink, attrPtr, flags)
  628.     char *pathName;
  629.     int fileOrLink;
  630.     Fs_Attributes *attrPtr;
  631.     int flags;
  632. {
  633.     register ReturnStatus status;
  634.     Proc_ControlBlock *procPtr = Proc_GetEffectiveProc();
  635.     Fs_SetAttrArgs setAttrArgs;        /* Bundled openArgs and attributes */
  636.     Fs_OpenArgs *openArgsPtr;        /* Pointer into setAttrArgs */
  637.     Fs_FileID ioFileID;            /* Used to get to I/O server */
  638.  
  639.     openArgsPtr = &setAttrArgs.openArgs;
  640.     openArgsPtr->useFlags = FS_OWNERSHIP;
  641.     if (fileOrLink == FS_ATTRIB_FILE) {
  642.     openArgsPtr->useFlags |= FS_FOLLOW;
  643.     }
  644.     openArgsPtr->permissions = 0;
  645.     openArgsPtr->type = FS_FILE;
  646.     openArgsPtr->clientID = rpc_SpriteID;
  647.     Fs_SetIDs(procPtr, &openArgsPtr->id);
  648.     if (procPtr->genFlags & PROC_FOREIGN) {
  649.     openArgsPtr->migClientID = procPtr->peerHostID;
  650.     } else {
  651.     openArgsPtr->migClientID = rpc_SpriteID;
  652.     }
  653.  
  654.     /*
  655.      * This copy is done here to avoid doing it in the client RPC stub.
  656.      */
  657.     setAttrArgs.attr = *attrPtr;
  658.     setAttrArgs.flags = flags;
  659.  
  660.     /*
  661.      * Set the attributes at the name server.  We get in return a fileID
  662.      * for the actual device which specifies a serverID.
  663.      */
  664.     fs_Stats.cltName.setAttrs++;
  665.     status = Fsprefix_LookupOperation(pathName, FS_DOMAIN_SET_ATTR, 0,
  666.              (Address)&setAttrArgs, (Address)&ioFileID,
  667.              (Fs_NameInfo *)NIL);
  668.     if ((status == SUCCESS) &&
  669.     (ioFileID.type > 0 && ioFileID.type <= FSIO_NUM_STREAM_TYPES)) {
  670.     /*
  671.      * Set the attributes at the I/O server.
  672.      */
  673.     fs_Stats.cltName.setIOAttrs++;
  674.     status = (*fsio_StreamOpTable[ioFileID.type].setIOAttr)
  675.             (&ioFileID, attrPtr, flags);
  676. #ifdef lint
  677.     status = Fsrmt_SetIOAttr(&ioFileID, attrPtr, flags);
  678.     status = FsrmtFileSetIOAttr(&ioFileID, attrPtr, flags);
  679.     status = Fsio_DeviceSetIOAttr(&ioFileID, attrPtr, flags);
  680.     status = Fsio_PipeSetIOAttr(&ioFileID, attrPtr, flags);
  681. #endif lint
  682.     }
  683.     return(status);
  684. }
  685.  
  686. /*
  687.  *----------------------------------------------------------------------
  688.  *
  689.  * Fs_HardLink --
  690.  *
  691.  *      Make two pathnames refer to the same file.  The pathnames are
  692.  *      restricted to be in the same domain, ie. stored on the same
  693.  *      disk pack, so the file server can make the link.
  694.  *
  695.  * Results:
  696.  *      SUCCESS if the link was made.  FS_CANT_LINK if the pathnames
  697.  *      are not in the same domain.
  698.  *
  699.  * Side effects:
  700.  *      Cause the two pathnames to refer to the same file.
  701.  *
  702.  *----------------------------------------------------------------------
  703.  */
  704. ReturnStatus
  705. Fs_HardLink(pathName, linkName)
  706.     char *pathName;    /* Name of the existing file */
  707.     char *linkName;    /* Name of the file to create which is a link to
  708.              * the existing file */
  709. {
  710.     ReturnStatus status;
  711.     Fs_LookupArgs lookupArgs;
  712.     Proc_ControlBlock *procPtr = Proc_GetEffectiveProc();
  713.  
  714.     lookupArgs.useFlags = FS_LINK;
  715.     Fs_SetIDs(procPtr, &lookupArgs.id);
  716.     lookupArgs.clientID = rpc_SpriteID;
  717.     if (procPtr->genFlags & PROC_FOREIGN) {
  718.     lookupArgs.migClientID    = procPtr->peerHostID;
  719.     } else {
  720.     lookupArgs.migClientID    = rpc_SpriteID;
  721.     }
  722.     fs_Stats.cltName.hardLinks++;
  723.     status = Fsprefix_TwoNameOperation(FS_DOMAIN_HARD_LINK, pathName, linkName,
  724.                              &lookupArgs);
  725.     return(status);
  726. }
  727.  
  728. /*
  729.  *----------------------------------------------------------------------
  730.  *
  731.  * Fs_Rename --
  732.  *
  733.  *    Change the name of a file.  This is complicated because the files
  734.  *    can only be in the same domain.  This is not directly evident.
  735.  *
  736.  * Results:
  737.  *      SUCCESS if the name was changed.
  738.  *
  739.  * Side effects:
  740.  *    Change the name of a file.
  741.  *
  742.  *----------------------------------------------------------------------
  743.  */
  744. ReturnStatus
  745. Fs_Rename(pathName, newName)
  746.     char *pathName;    /* Name of the existing file */
  747.     char *newName;    /* The new pathname for the file */
  748. {
  749.     ReturnStatus status;
  750.     Fs_LookupArgs lookupArgs;
  751.     Proc_ControlBlock *procPtr = Proc_GetEffectiveProc();
  752.  
  753.     lookupArgs.useFlags = FS_LINK | FS_RENAME;
  754.     Fs_SetIDs(procPtr, &lookupArgs.id);
  755.     lookupArgs.clientID = rpc_SpriteID;
  756.     if (procPtr->genFlags & PROC_FOREIGN) {
  757.     lookupArgs.migClientID    = procPtr->peerHostID;
  758.     } else {
  759.     lookupArgs.migClientID    = rpc_SpriteID;
  760.     }
  761.     fs_Stats.cltName.renames++;
  762.     status = Fsprefix_TwoNameOperation(FS_DOMAIN_RENAME, pathName, newName,
  763.                           &lookupArgs);
  764.     return(status);
  765. }
  766.  
  767. /*
  768.  *----------------------------------------------------------------------
  769.  *
  770.  * Fs_SymLink --
  771.  *
  772.  *    Create a symbolic link file by writing the name of the target
  773.  *    file (including the NULL) into the link file.  This only
  774.  *    succeeds if the link file does not already exist.
  775.  *
  776.  * Results:
  777.  *      SUCCESS if the link was created.
  778.  *
  779.  * Side effects:
  780.  *    Create the file and write the link name into it.
  781.  *
  782.  *----------------------------------------------------------------------
  783.  */
  784. ReturnStatus
  785. Fs_SymLink(targetName, linkName, remoteFlag)
  786.     char *targetName;    /* Name of the file to link to */
  787.     char *linkName;    /* The name of the new link file that's created */
  788.     Boolean remoteFlag;    /* TRUE => link will be a REMOTE_LINK */
  789. {
  790.     ReturnStatus status;
  791.     Fs_Stream *streamPtr;
  792.     int length;
  793.  
  794.     if (remoteFlag) {
  795.     /*
  796.      * Could check for super-user only here.
  797.      */
  798.     if (targetName[0] != '/') {
  799.         /*
  800.          * Remote links must be absolute.  They should also be circular,
  801.          * but that is harder to check.
  802.          */
  803.         return(FS_INVALID_ARG);
  804.     }
  805.     }
  806.     fs_Stats.cltName.symLinks++;
  807.     status = Fs_Open(linkName, FS_CREATE | FS_WRITE | FS_EXCLUSIVE,
  808.                 (remoteFlag ? FS_REMOTE_LINK : FS_SYMBOLIC_LINK),
  809.                 0777, &streamPtr);
  810.     if (status == SUCCESS) {
  811.     length = strlen(targetName) + 1;    /* FIX */
  812.     status = Fs_Write(streamPtr, targetName, 0, &length);
  813.     (void)Fs_Close(streamPtr);
  814.     }
  815.     return(status);
  816. }
  817.